﻿using MaterialDesignThemes.Wpf;
using System;
using System.Windows.Input;
using Json2Model;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.IO;

namespace Main.Domain
{
    internal class Json2ModelViewModel : INotifyPropertyChanged
    {
        public Json2ModelViewModel(ISnackbarMessageQueue snackbarMessageQueue)
        {
            _snackbarMessageQueue = snackbarMessageQueue ?? throw new ArgumentNullException(nameof(snackbarMessageQueue));
            CreateCommand = new AnotherCommandImplementation(createModel);
            SaveAsFileCommand = new AnotherCommandImplementation(saveAsFile);
        }


        private readonly ISnackbarMessageQueue _snackbarMessageQueue;
        public CodeCompiler Compiler { get; set; } = new CodeCompiler();
        private string jsonStr;
        public string JsonStr
        {
            get => jsonStr;
            set
            {
                jsonStr = value;
                OnPropertyChanged();
            }
        }
        public bool SaveAsSingle { get; set; } = false;
        public ICommand SaveAsFileCommand { get; }
        public ICommand CreateCommand { get; }
        public bool IsCanSave
        {
            get => models != null && models.Count > 0;
        }
        private string rootClassName = "Root";
        public string RootClassName
        {
            get => rootClassName;
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                    rootClassName = "Root";
                else
                    rootClassName = value;
            }
        }
        private Dictionary<string, string> ModelsDic;
        private ObservableCollection<JModel> models;
        public ObservableCollection<JModel> Models
        {
            get => models;
            set
            {
                models = value;
                OnPropertyChanged();
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsCanSave"));
            }
        }
        public string ArrayType
        {
            get => JObjectFormater.ArrayType;
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                    JObjectFormater.ArrayType = "IList";
                else
                    JObjectFormater.ArrayType = value;
            }
        }
        private JModel selectModel;
        public JModel SelectModel
        {
            get { return selectModel; }
            set
            {
                selectModel = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectModel"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectModelClass"));
            }
        }
        public string SelectModelClass
        {
            get
            {
                if (SelectModel != null && ModelsDic != null && ModelsDic.ContainsKey(Converter.TypeNameFormat(SelectModel.Name)))
                    return ModelsDic[Converter.TypeNameFormat(SelectModel.Name)];
                else return string.Empty;
            }
        }

        private void createModel(object obj)
        {
            try
            {
                JObjectFormater jObjectFormater = new JObjectFormater();
                JsonStr = jObjectFormater.Format(JsonStr);
                Models = new ObservableCollection<JModel>(jObjectFormater.Format(JsonStr, RootClassName));
                ModelsDic = new Dictionary<string, string>();

                if (SaveAsSingle)
                {
                    ModelsDic[RootClassName] = Compiler.CompileClasses(Models);
                    Models.Clear();
                    Models.Add(new JModel { Name = RootClassName });
                }
                else
                {
                    foreach (var model in Models)
                    {
                        ModelsDic[Converter.TypeNameFormat(model.Name)] = Compiler.CompileClass(model);
                    }
                }
                if (Models.Count > 0)
                    SelectModel = Models[Models.Count - 1];
            }
            catch (Exception ex)
            {
                _snackbarMessageQueue.Enqueue(ex);
            }
        }

        string SavePath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

        private void saveAsFile(object obj)
        {
            if (ModelsDic != null && ModelsDic.Count > 0)
            {
                string path = Path.Combine(SavePath, "Models");
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                foreach (var kv in ModelsDic)
                {
                    using TextWriter tw = new StreamWriter(Path.Combine(path, kv.Key + ".cs"));
                    tw.WriteLine(kv.Value);
                    tw.Close();
                }
                _snackbarMessageQueue.Enqueue("已保存至桌面Models文件夹下！");
            }

        }


        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
